<!DOCTYPE html>
<!--
  UsbKVM Pro - Professional WebUSB KVM Controller
  Version: 1.0.0
  Copyright (c) 2025 DarkAthena (darkathena@qq.com)
-->
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>UsbKVM Pro - Professional WebUSB KVM Controller</title>
  <style>
    * { box-sizing: border-box; }
    body { 
      margin: 0; padding: 10px; 
      font-family: Arial, sans-serif;
      background: #1e1e1e; color: #fff;
    }
    .container { max-width: 1200px; margin: 0 auto; }
    .controls { 
      display: flex; gap: 10px; margin-bottom: 10px; 
      flex-wrap: wrap; align-items: center;
    }
    button, select { 
      padding: 8px 12px; border: none; border-radius: 4px;
      background: #333; color: #fff; cursor: pointer;
    }
    button:hover, select:hover { background: #555; }
    button:active { background: #666; }
    .status { 
      padding: 5px 10px; border-radius: 4px; margin-left: 10px;
      font-size: 12px; 
    }
    .status.connected { background: #2d5a27; }
    .status.disconnected { background: #5a2727; }
    #monitor { 
      width: 100%; max-width: 100%; height: auto;
      border: 2px solid #444; border-radius: 4px;
      background: #000; cursor: crosshair;
      object-fit: contain; /* 默认保持比例 */
    }
    #monitor.original-size {
      width: auto; height: auto; max-width: none; max-height: none;
      object-fit: none;
    }
    #monitor.fit-screen {
      width: 100%; height: auto; max-height: 80vh;
      object-fit: contain;
    }
    #monitor.stretch-fill {
      width: 100%; height: 60vh;
      object-fit: fill;
    }
    #monitor::-webkit-media-controls {
      display: none !important;
    }
    #monitor::-webkit-media-controls-panel {
      display: none !important;
    }
    #monitor::-webkit-media-controls-play-button {
      display: none !important;
    }
    #monitor::-webkit-media-controls-start-playback-button {
      display: none !important;
    }
    video::-webkit-media-controls {
      display: none !important;
    }
    video::-webkit-media-controls-enclosure {
      display: none !important;
    }
    #monitor:focus { border-color: #0078d4; outline: none; }
    #monitor.mouse-locked { border-color: #ff6b35; box-shadow: 0 0 10px rgba(255, 107, 53, 0.5); }
    .key-pressed { background: #0078d4 !important; }
    .input-status {
      position: absolute; top: 10px; left: 10px;
      background: rgba(0, 0, 0, 0.7); color: #fff;
      padding: 5px 10px; border-radius: 4px;
      font-size: 12px; display: none;
    }
    .input-status.show { display: block; }
    .overlay {
      position: fixed; top: 0; left: 0; right: 0; bottom: 0;
      background: rgba(0,0,0,0.8); display: none;
      justify-content: center; align-items: center;
      z-index: 1000;
    }
    .overlay.show { display: flex; }
    .modal {
      background: #2d2d2d; padding: 20px; border-radius: 8px;
      min-width: 300px; text-align: center;
    }
    textarea {
      width: 100%; height: 60px; margin: 10px 0;
      background: #333; color: #fff; border: 1px solid #555;
      border-radius: 4px; padding: 8px; resize: vertical;
    }
    .shortcuts-panel {
      background: #2d2d2d; border-radius: 6px; padding: 10px;
      margin: 8px 0; border: 1px solid #444;
    }
    .shortcuts-panel h3 {
      margin: 0 0 8px 0; color: #0078d4;
      font-size: 14px; display: flex; align-items: center;
    }
    .shortcuts-grid {
      display: grid; grid-template-columns: 1fr 1fr 1fr;
      gap: 6px; font-size: 11px;
    }
    .shortcut-item {
      background: #333; padding: 4px 6px; border-radius: 3px;
      display: flex; justify-content: space-between;
    }
    .shortcut-key {
      color: #87ceeb; font-family: monospace;
      font-weight: bold; font-size: 10px;
    }
    .shortcut-desc { color: #ccc; font-size: 10px; }
  </style>
</head>
<body>
  <div class="container">
    <div class="controls">
      <button id="initBtn">🔌 Connect</button>
      <button id="captureBtn" disabled>📹 Capture Video</button>
      <button id="deviceBtn" disabled>📱 Select Device</button>
      <button id="mouseBtn" disabled>🖱️ Lock Mouse</button>
      <button id="fullscreenBtn" disabled>⛶ Fullscreen</button>
      <select id="quickKeys">
        <option value="">Quick Keys</option>
        <option value="ctrl_alt_del">Ctrl+Alt+Del</option>
        <option value="alt_f4">Alt+F4</option>
        <option value="ctrl_c">Ctrl+C</option>
        <option value="ctrl_v">Ctrl+V</option>
        <option value="win_r">Win+R</option>
      </select>
      <button id="pasteBtn" disabled>📋 Paste</button>
      <button id="capsBtn" disabled>🔠 Sync Caps</button>
      <button id="resetBtn" disabled>🔄 Reset Keys</button>
      <select id="resolutionSelect">
        <option value="">Display Mode</option>
        <option value="original">Original Size</option>
        <option value="fit">Fit to Screen</option>
        <option value="stretch">Stretch to Fill</option>
      </select>
      <select id="framerateSelect">
        <option value="">Frame Rate</option>
        <option value="15">15 FPS</option>
        <option value="30">30 FPS</option>
        <option value="60">60 FPS</option>
      </select>
      <select id="sensitivitySelect">
        <option value="">Mouse Sensitivity</option>
        <option value="0.5">Low (0.5x)</option>
        <option value="0.8">Normal (0.8x)</option>
        <option value="1.0">High (1.0x)</option>
        <option value="1.5">Very High (1.5x)</option>
      </select>
      <button id="testBtn" disabled>🧪 Test Shift</button>
      <button id="testSeqBtn" disabled>📝 Test Sequence</button>
      <span class="status disconnected" id="status">Disconnected</span>
    </div>

    <!-- 快捷键说明面板 -->
    <div class="shortcuts-panel">
      <h3>⌨️ 快捷键说明</h3>
      <div class="shortcuts-grid">
        <div class="shortcut-item">
          <span class="shortcut-key">F11</span>
          <span class="shortcut-desc">全屏+锁鼠标</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">ESC</span>
          <span class="shortcut-desc">退出全屏</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">Ctrl+L</span>
          <span class="shortcut-desc">锁定鼠标</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">Ctrl+V</span>
          <span class="shortcut-desc">快捷粘贴</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">Reset Keys</span>
          <span class="shortcut-desc">清理按键状态</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">鼠标滚轮</span>
          <span class="shortcut-desc">滚动支持</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">鼠标拖拽</span>
          <span class="shortcut-desc">拖放支持</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">鼠标灵敏度</span>
          <span class="shortcut-desc">速度调节</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">Frame Rate</span>
          <span class="shortcut-desc">帧率切换</span>
        </div>
        <div class="shortcut-item">
          <span class="shortcut-key">仅英文</span>
          <span class="shortcut-desc">粘贴限制</span>
        </div>
      </div>
    </div>

    <div style="position: relative;">
      <video id="monitor" tabindex="0" autoplay muted playsinline 
             controls="false" 
             disablePictureInPicture 
             controlsList="nodownload nofullscreen noremoteplayback"
             style="pointer-events: auto;"></video>
      <div class="input-status" id="inputStatus">🎯 Input Active</div>
    </div>
  </div>

  <!-- 粘贴文本对话框 -->
  <div class="overlay" id="pasteModal">
    <div class="modal">
      <h3>Paste Text</h3>
      <p style="font-size: 12px; color: #ccc; margin: 5px 0;">
        仅支持英文、数字和符号。中文需要在目标系统切换输入法后手动输入。
      </p>
      <textarea id="pasteText" placeholder="输入英文文本（不支持中文）..."></textarea>
      <div>
        <button onclick="sendPasteText()">Send</button>
        <button onclick="closePasteModal()">Cancel</button>
      </div>
    </div>
  </div>

  <script>
    // 全局状态
    let serialPort = null;
    let mediaStream = null;
    let isConnected = false;
    let isCapturing = false;
    let pressedKeys = new Set();
    let keyRepeatTimer = null;
    let currentModifiers = 0; // 跟踪当前修饰键状态
    let pressedModifiers = new Set(); // 跟踪按下的修饰键
    let currentFrameRate = 30; // 当前帧率设置
    let mouseSensitivity = 0.8; // 鼠标灵敏度

    // DOM 元素
    const elements = {
      initBtn: document.getElementById('initBtn'),
      captureBtn: document.getElementById('captureBtn'),
      deviceBtn: document.getElementById('deviceBtn'),
      mouseBtn: document.getElementById('mouseBtn'),
      fullscreenBtn: document.getElementById('fullscreenBtn'),
      quickKeys: document.getElementById('quickKeys'),
      pasteBtn: document.getElementById('pasteBtn'),
      capsBtn: document.getElementById('capsBtn'),
      resetBtn: document.getElementById('resetBtn'),
      resolutionSelect: document.getElementById('resolutionSelect'),
      framerateSelect: document.getElementById('framerateSelect'),
      sensitivitySelect: document.getElementById('sensitivitySelect'),
      testBtn: document.getElementById('testBtn'),
      testSeqBtn: document.getElementById('testSeqBtn'),
      status: document.getElementById('status'),
      monitor: document.getElementById('monitor'),
      pasteModal: document.getElementById('pasteModal'),
      pasteText: document.getElementById('pasteText'),
      inputStatus: document.getElementById('inputStatus')
    };

    // USB HID 键码映射（完整版）
    const KEY_CODES = {
      // 字母键 - 大小写统一映射到同一个键码
      'a': 0x04, 'A': 0x04, 'b': 0x05, 'B': 0x05, 'c': 0x06, 'C': 0x06, 
      'd': 0x07, 'D': 0x07, 'e': 0x08, 'E': 0x08, 'f': 0x09, 'F': 0x09,
      'g': 0x0a, 'G': 0x0a, 'h': 0x0b, 'H': 0x0b, 'i': 0x0c, 'I': 0x0c, 
      'j': 0x0d, 'J': 0x0d, 'k': 0x0e, 'K': 0x0e, 'l': 0x0f, 'L': 0x0f,
      'm': 0x10, 'M': 0x10, 'n': 0x11, 'N': 0x11, 'o': 0x12, 'O': 0x12, 
      'p': 0x13, 'P': 0x13, 'q': 0x14, 'Q': 0x14, 'r': 0x15, 'R': 0x15,
      's': 0x16, 'S': 0x16, 't': 0x17, 'T': 0x17, 'u': 0x18, 'U': 0x18, 
      'v': 0x19, 'V': 0x19, 'w': 0x1a, 'W': 0x1a, 'x': 0x1b, 'X': 0x1b,
      'y': 0x1c, 'Y': 0x1c, 'z': 0x1d, 'Z': 0x1d,
      
      // 数字键和符号
      '1': 0x1e, '!': 0x1e, '2': 0x1f, '@': 0x1f, '3': 0x20, '#': 0x20,
      '4': 0x21, '$': 0x21, '5': 0x22, '%': 0x22, '6': 0x23, '^': 0x23,
      '7': 0x24, '&': 0x24, '8': 0x25, '*': 0x25, '9': 0x26, '(': 0x26,
      '0': 0x27, ')': 0x27,
      
      // 标点符号
      '-': 0x2d, '_': 0x2d, '=': 0x2e, '+': 0x2e,
      '[': 0x2f, '{': 0x2f, ']': 0x30, '}': 0x30,
      '\\': 0x31, '|': 0x31, ';': 0x33, ':': 0x33,
      "'": 0x34, '"': 0x34, '`': 0x35, '~': 0x35,
      ',': 0x36, '<': 0x36, '.': 0x37, '>': 0x37,
      '/': 0x38, '?': 0x38,
      
      // 功能键
      'Enter': 0x28, 'Escape': 0x29, 'Backspace': 0x2a, 'Tab': 0x2b,
      ' ': 0x2c, 'Space': 0x2c,
      'F1': 0x3a, 'F2': 0x3b, 'F3': 0x3c, 'F4': 0x3d, 'F5': 0x3e,
      'F6': 0x3f, 'F7': 0x40, 'F8': 0x41, 'F9': 0x42, 'F10': 0x43,
      'F11': 0x44, 'F12': 0x45,
      
      // 方向键
      'ArrowLeft': 0x50, 'ArrowDown': 0x51, 'ArrowUp': 0x52, 'ArrowRight': 0x4f,
      
      // 修饰键 - 左右区分
      'Control': 0xe0, 'ControlLeft': 0xe0, 'ControlRight': 0xe4,
      'Shift': 0xe1, 'ShiftLeft': 0xe1, 'ShiftRight': 0xe5,
      'Alt': 0xe2, 'AltLeft': 0xe2, 'AltRight': 0xe6,
      'Meta': 0xe3, 'MetaLeft': 0xe3, 'MetaRight': 0xe7,
      
      // 其他键
      'Delete': 0x4c, 'Home': 0x4a, 'End': 0x4d, 'PageUp': 0x4b, 'PageDown': 0x4e,
      'Insert': 0x49, 'CapsLock': 0x39
    };

    // 需要Shift键的字符映射
    const SHIFT_CHARS = new Set([
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
      '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
      '_', '+', '{', '}', '|', ':', '"', '~', '<', '>', '?'
    ]);

    // 修饰键映射 - 支持左右区分（USB HID标准）
    const MODIFIER_BITS = {
      'Control': 0x01, 'ControlLeft': 0x01, 'ControlRight': 0x10,
      'Shift': 0x02, 'ShiftLeft': 0x02, 'ShiftRight': 0x20,
      'Alt': 0x04, 'AltLeft': 0x04, 'AltRight': 0x40,
      'Meta': 0x08, 'MetaLeft': 0x08, 'MetaRight': 0x80
    };

    // 生成数据包
    function createPacket(cmd, ...data) {
      const packet = [0x57, 0xab, 0x00, cmd, data.length, ...data];
      const checksum = packet.reduce((sum, byte) => (sum + byte) % 256, 0);
      packet.push(checksum);
      return new Uint8Array(packet);
    }

    // 更新状态显示
    function updateStatus(connected) {
      isConnected = connected;
      elements.status.textContent = connected ? 'Connected' : 'Disconnected';
      elements.status.className = `status ${connected ? 'connected' : 'disconnected'}`;
      
      elements.captureBtn.disabled = !connected;
      elements.deviceBtn.disabled = !connected;
      elements.mouseBtn.disabled = !connected;
      elements.fullscreenBtn.disabled = !connected;
      elements.pasteBtn.disabled = !connected;
      elements.capsBtn.disabled = !connected;
      elements.resetBtn.disabled = !connected;
      elements.testBtn.disabled = !connected;
      elements.testSeqBtn.disabled = !connected;
      
      elements.initBtn.textContent = connected ? '🔌 Disconnect' : '🔌 Connect';
    }

    // 初始化连接
    async function initConnection() {
      if (isConnected) {
        // 断开连接
        if (serialPort) {
          try { await serialPort.close(); } catch(e) {}
          serialPort = null;
        }
        if (mediaStream) {
          mediaStream.getTracks().forEach(track => track.stop());
          mediaStream = null;
        }
        elements.monitor.srcObject = null;
        updateStatus(false);
        return;
      }

      try {
        // 连接串口（自动使用默认波特率9600）
        if ('serial' in navigator) {
          serialPort = await navigator.serial.requestPort();
          await serialPort.open({ baudRate: 9600 });
        } else {
          throw new Error('WebSerial not supported');
        }

        updateStatus(true);
        elements.captureBtn.disabled = false;
        
        // 强化键盘状态初始化 - 发送完整的初始化序列
        try {
          const writer = serialPort.writable.getWriter();
          // 1. 先发送一个清空包
          await writer.write(createPacket(0x02, 0, 0, 0, 0, 0, 0, 0, 0));
          await new Promise(resolve => setTimeout(resolve, 10));
          
          // 2. 发送所有修饰键的释放状态
          await writer.write(createPacket(0x02, 0, 0, 0, 0, 0, 0, 0, 0));
          await new Promise(resolve => setTimeout(resolve, 10));
          
          // 3. 再次发送清空包确保状态同步
          await writer.write(createPacket(0x02, 0, 0, 0, 0, 0, 0, 0, 0));
          
          writer.releaseLock();
          console.log('Enhanced keyboard state initialization completed');
        } catch (error) {
          console.warn('Failed to initialize keyboard state:', error);
        }
        
      } catch (error) {
        console.error('Connection failed:', error);
        alert('连接失败：' + error.message);
      }
    }

    // 开始视频捕获（外部设备）
    async function startCapture() {
      if (isCapturing) {
        // 停止捕获
        if (mediaStream) {
          mediaStream.getTracks().forEach(track => track.stop());
          mediaStream = null;
        }
        elements.monitor.srcObject = null;
        isCapturing = false;
        elements.captureBtn.textContent = '📹 Capture Video';
        return;
      }

      try {
        // 获取所有视频设备
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');
        
        // 如果只有一个设备，直接使用；否则让用户选择
        let deviceId = null;
        if (videoDevices.length === 1) {
          deviceId = videoDevices[0].deviceId;
        } else if (videoDevices.length > 1) {
          // 优先选择非默认设备（通常是外部采集卡）
          const externalDevice = videoDevices.find(device => 
            device.label.toLowerCase().includes('capture') ||
            device.label.toLowerCase().includes('hdmi') ||
            device.label.toLowerCase().includes('usb') ||
            !device.label.toLowerCase().includes('integrated') &&
            !device.label.toLowerCase().includes('built-in')
          );
          deviceId = externalDevice ? externalDevice.deviceId : videoDevices[1].deviceId;
        }

        // 捕获外部视频源
        mediaStream = await navigator.mediaDevices.getUserMedia({
          video: {
            deviceId: deviceId ? { exact: deviceId } : undefined,
            frameRate: { ideal: currentFrameRate, min: Math.min(15, currentFrameRate) },
            width: { ideal: 1920, min: 1280 },
            height: { ideal: 1080, min: 720 }
          },
          audio: false // KVM通常不需要音频
        });

        elements.monitor.srcObject = mediaStream;
        elements.monitor.focus();
        
        // 禁用视频播放器控件
        elements.monitor.controls = false;
        elements.monitor.disablePictureInPicture = true;
        elements.monitor.setAttribute('controlsList', 'nodownload nofullscreen noremoteplayback');
        
        // 直接在视频元素上阻止空格键事件，但转发给KVM处理
        elements.monitor.addEventListener('keydown', (e) => {
          if (e.key === ' ' || e.key === 'Space') {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            
            // 手动触发KVM的键盘处理
            if (isConnected && (document.activeElement === elements.monitor || document.pointerLockElement)) {
              handleKeyDown(e);
            }
            return false;
          }
        }, true);
        
        elements.monitor.addEventListener('keyup', (e) => {
          if (e.key === ' ' || e.key === 'Space') {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            
            // 手动触发KVM的键盘处理
            if (isConnected && (document.activeElement === elements.monitor || document.pointerLockElement)) {
              handleKeyUp(e);
            }
            return false;
          }
        }, true);
        
        // 防止右键菜单
        elements.monitor.addEventListener('contextmenu', (e) => e.preventDefault());
        
        isCapturing = true;
        elements.captureBtn.textContent = '📹 Stop Capture';

        // 监听流结束事件
        mediaStream.getVideoTracks()[0].onended = () => {
          isCapturing = false;
          elements.captureBtn.textContent = '📹 Capture Video';
        };

        console.log('Using video device:', mediaStream.getVideoTracks()[0].label);

      } catch (error) {
        console.error('Capture failed:', error);
        
        // 如果自动选择失败，提示用户手动选择
        if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {
          alert('未找到外部视频设备。请确保HDMI采集卡或USB摄像头已连接并被系统识别。');
        } else if (error.name === 'NotAllowedError') {
          alert('需要摄像头权限才能捕获外部视频。');
        } else {
          alert('捕获失败：' + error.message);
        }
      }
    }

    // 手动选择视频设备
    async function selectVideoDevice() {
      try {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');
        
        if (videoDevices.length === 0) {
          alert('未找到任何视频设备');
          return;
        }

        // 创建设备选择对话框
        const deviceList = videoDevices.map((device, index) => 
          `${index + 1}. ${device.label || `设备 ${index + 1}`}`
        ).join('\n');
        
        const choice = prompt(`选择视频设备:\n${deviceList}\n\n请输入设备编号 (1-${videoDevices.length}):`);
        
        if (!choice) return;
        
        const deviceIndex = parseInt(choice) - 1;
        if (deviceIndex < 0 || deviceIndex >= videoDevices.length) {
          alert('无效的设备编号');
          return;
        }

        const selectedDevice = videoDevices[deviceIndex];
        
        // 停止当前流
        if (mediaStream) {
          mediaStream.getTracks().forEach(track => track.stop());
        }

        // 使用选择的设备
        mediaStream = await navigator.mediaDevices.getUserMedia({
          video: {
            deviceId: { exact: selectedDevice.deviceId },
            frameRate: { ideal: currentFrameRate, min: Math.min(15, currentFrameRate) },
            width: { ideal: 1920, min: 1280 },
            height: { ideal: 1080, min: 720 }
          },
          audio: false
        });

        elements.monitor.srcObject = mediaStream;
        
        // 禁用视频播放器控件
        elements.monitor.controls = false;
        elements.monitor.disablePictureInPicture = true;
        elements.monitor.setAttribute('controlsList', 'nodownload nofullscreen noremoteplayback');
        
        // 直接在视频元素上阻止空格键事件，但转发给KVM处理
        elements.monitor.addEventListener('keydown', (e) => {
          if (e.key === ' ' || e.key === 'Space') {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            
            // 手动触发KVM的键盘处理
            if (isConnected && (document.activeElement === elements.monitor || document.pointerLockElement)) {
              handleKeyDown(e);
            }
            return false;
          }
        }, true);
        
        elements.monitor.addEventListener('keyup', (e) => {
          if (e.key === ' ' || e.key === 'Space') {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            
            // 手动触发KVM的键盘处理
            if (isConnected && (document.activeElement === elements.monitor || document.pointerLockElement)) {
              handleKeyUp(e);
            }
            return false;
          }
        }, true);
        
        isCapturing = true;
        elements.captureBtn.textContent = '📹 Stop Capture';
        
        console.log('Switched to device:', selectedDevice.label);

      } catch (error) {
        console.error('Device selection failed:', error);
        alert('设备选择失败：' + error.message);
      }
    }

    // 发送键盘事件
    async function sendKeyEvent(keyCode, modifiers = 0, pressed = true) {
      if (!serialPort) return;
      
      try {
        const writer = serialPort.writable.getWriter();
        
        if (pressed) {
          // 按下：发送修饰键 + 主键
          // CH9329协议：修饰键在第6字节，主键在第8字节
          const packet = createPacket(0x02, modifiers, 0, keyCode, 0, 0, 0, 0, 0);
          await writer.write(packet);
          console.log(`Sent KeyDown: KeyCode=0x${keyCode.toString(16)}, Modifiers=0x${modifiers.toString(16)}, Packet:`, Array.from(packet).map(b => '0x' + b.toString(16).padStart(2, '0')).join(' '));
        } else {
          // 释放：清除主键，保持修饰键状态
          const packet = createPacket(0x02, modifiers, 0, 0, 0, 0, 0, 0, 0);
          await writer.write(packet);
          console.log(`Sent KeyUp: Modifiers=0x${modifiers.toString(16)}, Packet:`, Array.from(packet).map(b => '0x' + b.toString(16).padStart(2, '0')).join(' '));
        }
        
        writer.releaseLock();
      } catch (error) {
        console.error('Send key failed:', error);
      }
    }

    // 发送鼠标事件 - 优化版本
    async function sendMouseEvent(buttons, deltaX, deltaY, wheel = 0) {
      if (!serialPort) return;
      
      // 提前计算所有值，减少处理时间
      deltaX = Math.max(-127, Math.min(127, Math.round(deltaX)));
      deltaY = Math.max(-127, Math.min(127, Math.round(deltaY)));
      wheel = Math.max(-127, Math.min(127, Math.round(wheel)));
      
      // 优化负数处理
      const finalDeltaX = deltaX < 0 ? (256 + deltaX) : deltaX;
      const finalDeltaY = deltaY < 0 ? (256 + deltaY) : deltaY;
      const finalWheel = wheel < 0 ? (256 + wheel) : wheel;
      
      try {
        const writer = serialPort.writable.getWriter();
        const packet = createPacket(0x05, 1, buttons, finalDeltaX, finalDeltaY, finalWheel);
        await writer.write(packet);
        writer.releaseLock();
      } catch (error) {
        console.error('Send mouse failed:', error);
      }
    }

    // 清理所有按键状态
    function clearAllKeyStates() {
      pressedKeys.clear();
      pressedModifiers.clear();
      currentModifiers = 0;
      
      if (keyRepeatTimer) {
        clearTimeout(keyRepeatTimer);
        keyRepeatTimer = null;
      }
      
      // 清理鼠标按钮状态
      if (currentMouseButtons !== 0) {
        currentMouseButtons = 0;
        if (isConnected && serialPort) {
          sendMouseEvent(0, 0, 0);
        }
      }
      
      // 发送多次清空状态到远程端，确保状态同步
      if (isConnected && serialPort) {
        // 发送3次清空包，确保远程设备收到
        setTimeout(() => sendKeyEvent(0, 0, false), 0);
        setTimeout(() => sendKeyEvent(0, 0, false), 50);
        setTimeout(() => sendKeyEvent(0, 0, false), 100);
        console.log('All key and mouse states cleared with redundancy');
      }
    }

    // 键盘事件处理
    function handleKeyDown(e) {
      if (!isConnected) return;
      
      e.preventDefault();
      
      const key = e.key;
      const keyCode = KEY_CODES[key];
      
      if (!keyCode) {
        console.log('Unsupported key:', key);
        return;
      }
      
      // 防止重复按键
      const keyId = `${key}_${e.ctrlKey}_${e.shiftKey}_${e.altKey}_${e.metaKey}`;
      if (pressedKeys.has(keyId)) return;
      pressedKeys.add(keyId);
      
      // 处理修饰键 - 从事件获取实时状态
      let modifiers = 0;
      if (e.ctrlKey) modifiers |= MODIFIER_BITS.Control;
      if (e.shiftKey) modifiers |= MODIFIER_BITS.Shift;
      if (e.altKey) modifiers |= MODIFIER_BITS.Alt;
      if (e.metaKey) modifiers |= MODIFIER_BITS.Meta;
      
      // 如果是修饰键本身，记录状态但不发送键码
      if (['Control', 'ControlLeft', 'ControlRight', 'Shift', 'ShiftLeft', 'ShiftRight', 
           'Alt', 'AltLeft', 'AltRight', 'Meta', 'MetaLeft', 'MetaRight'].includes(key)) {
        pressedModifiers.add(key);
        currentModifiers = modifiers;
        console.log(`Modifier key pressed: ${key}, updating state to 0x${modifiers.toString(16)}`);
        
        // 修饰键单独按下时，不发送任何键码，只更新状态
        // USB HID协议中，修饰键状态通过修饰符字段传递，不需要键码
        return;
      }
      
      console.log(`KeyDown: ${key}, KeyCode: 0x${keyCode.toString(16)}, Modifiers: 0x${modifiers.toString(16)}, Event: ctrl=${e.ctrlKey} shift=${e.shiftKey} alt=${e.altKey} meta=${e.metaKey}, Location: ${e.location}, Code: ${e.code}`);
      
      // 对于普通键，使用修饰符但不发送修饰键键码
      if (modifiers !== 0) {
        console.log(`Sending key with modifiers: ${key} + modifiers=0x${modifiers.toString(16)}`);
        setTimeout(() => {
          sendKeyEvent(keyCode, modifiers, true);
        }, 10); // 10ms延迟，确保修饰键状态同步
      } else {
        sendKeyEvent(keyCode, modifiers, true);
      }
      
      // 长按支持
      if (keyRepeatTimer) clearTimeout(keyRepeatTimer);
      keyRepeatTimer = setTimeout(() => {
        if (pressedKeys.has(keyId)) {
          // 持续发送按键事件
          const repeatInterval = setInterval(() => {
            if (!pressedKeys.has(keyId)) {
              clearInterval(repeatInterval);
              return;
            }
            sendKeyEvent(keyCode, modifiers, true);
          }, 50); // 每50ms重复一次
        }
      }, 500); // 500ms后开始重复
    }

    function handleKeyUp(e) {
      if (!isConnected) return;
      
      e.preventDefault();
      
      const key = e.key;
      const keyId = `${key}_${e.ctrlKey}_${e.shiftKey}_${e.altKey}_${e.metaKey}`;
      pressedKeys.delete(keyId);
      
      // 获取键码
      const keyCode = KEY_CODES[key] || 0;
      
      // 计算当前修饰键状态（不包括正在释放的键）
      let modifiers = 0;
      if (e.ctrlKey && !['Control', 'ControlLeft', 'ControlRight'].includes(key)) {
        modifiers |= MODIFIER_BITS.Control;
      }
      if (e.shiftKey && !['Shift', 'ShiftLeft', 'ShiftRight'].includes(key)) {
        modifiers |= MODIFIER_BITS.Shift;
      }
      if (e.altKey && !['Alt', 'AltLeft', 'AltRight'].includes(key)) {
        modifiers |= MODIFIER_BITS.Alt;
      }
      if (e.metaKey && !['Meta', 'MetaLeft', 'MetaRight'].includes(key)) {
        modifiers |= MODIFIER_BITS.Meta;
      }
      
      // 如果是修饰键本身，更新状态但不发送键码
      if (['Control', 'ControlLeft', 'ControlRight', 'Shift', 'ShiftLeft', 'ShiftRight', 
           'Alt', 'AltLeft', 'AltRight', 'Meta', 'MetaLeft', 'MetaRight'].includes(key)) {
        pressedModifiers.delete(key);
        currentModifiers = modifiers;
        console.log(`Modifier key released: ${key}, updating state to 0x${modifiers.toString(16)}`);
        
        // 修饰键单独释放时，不发送任何键码，只更新状态
        // USB HID协议中，修饰键状态通过修饰符字段传递，不需要键码
        return;
      }
      
      console.log(`KeyUp: ${key}, KeyCode: 0x${keyCode.toString(16)}, Modifiers: 0x${modifiers.toString(16)}`);
      
      if (keyRepeatTimer) {
        clearTimeout(keyRepeatTimer);
        keyRepeatTimer = null;
      }
      
      // 对于普通键，使用当前修饰符状态
      sendKeyEvent(keyCode, modifiers, false);
    }

    // 鼠标事件处理 - 优化性能版本
    let mouseAccumX = 0, mouseAccumY = 0;
    let mouseThrottleTimer = null;
    let lastMouseSendTime = 0;
    let currentMouseButtons = 0; // 跟踪当前按下的鼠标按钮状态

    function handleMouseMove(e) {
      if (!document.pointerLockElement) return;
      
      mouseAccumX += e.movementX;
      mouseAccumY += e.movementY;
      
      const now = performance.now();
      
      // 如果移动量足够大或者时间间隔足够，立即发送
      const movementMagnitude = Math.abs(mouseAccumX) + Math.abs(mouseAccumY);
      const timeSinceLastSend = now - lastMouseSendTime;
      
      if (movementMagnitude >= 3 || timeSinceLastSend >= 8) {
        // 立即发送，提高响应速度，包含当前按钮状态
        if (mouseThrottleTimer) {
          clearTimeout(mouseThrottleTimer);
          mouseThrottleTimer = null;
        }
        
        sendMouseEvent(currentMouseButtons, mouseAccumX * mouseSensitivity, mouseAccumY * mouseSensitivity, 0);
        mouseAccumX = mouseAccumY = 0;
        lastMouseSendTime = now;
        return;
      }
      
      // 对于小幅移动，使用更短的延迟
      if (mouseThrottleTimer) return;
      
      mouseThrottleTimer = setTimeout(() => {
        if (Math.abs(mouseAccumX) > 0 || Math.abs(mouseAccumY) > 0) {
          sendMouseEvent(currentMouseButtons, mouseAccumX * mouseSensitivity, mouseAccumY * mouseSensitivity, 0);
          mouseAccumX = mouseAccumY = 0;
          lastMouseSendTime = performance.now();
        }
        mouseThrottleTimer = null;
      }, 8); // 减少到8ms，约120fps
    }

    function handleMouseDown(e) {
      if (!document.pointerLockElement) return;
      
      e.preventDefault();
      
      // 更新按钮状态
      let buttons = 0;
      if (e.buttons & 1) buttons |= 0x01; // 左键
      if (e.buttons & 2) buttons |= 0x02; // 右键  
      if (e.buttons & 4) buttons |= 0x04; // 中键
      
      currentMouseButtons = buttons;
      sendMouseEvent(buttons, 0, 0);
      
      console.log(`Mouse down: buttons=0x${buttons.toString(16)}`);
    }

    function handleMouseUp(e) {
      if (!document.pointerLockElement) return;
      
      e.preventDefault();
      
      // 更新按钮状态
      let buttons = 0;
      if (e.buttons & 1) buttons |= 0x01; // 左键
      if (e.buttons & 2) buttons |= 0x02; // 右键
      if (e.buttons & 4) buttons |= 0x04; // 中键
      
      currentMouseButtons = buttons;
      sendMouseEvent(buttons, 0, 0);
      
      console.log(`Mouse up: buttons=0x${buttons.toString(16)}`);
    }

    // 兼容性保持 - 旧的 handleMouseClick 函数
    function handleMouseClick(e) {
      // 这个函数现在由 handleMouseDown 和 handleMouseUp 处理
      // 保留以防其他地方调用
      return;
    }

    // 鼠标上下文菜单事件处理（防止右键菜单并确保按钮状态）
    function handleContextMenu(e) {
      if (!document.pointerLockElement) return;
      e.preventDefault();
      e.stopPropagation();
      return false;
    }

    // 鼠标离开区域时清理按钮状态
    function handleMouseLeave(e) {
      if (!document.pointerLockElement) return;
      
      // 清理所有按钮状态
      if (currentMouseButtons !== 0) {
        currentMouseButtons = 0;
        sendMouseEvent(0, 0, 0);
        console.log('Mouse left area, clearing button states');
      }
    }

    // 鼠标滚轮事件处理
    function handleMouseWheel(e) {
      if (!document.pointerLockElement) return;
      
      e.preventDefault();
      
      // 获取滚轮滚动方向和强度
      let wheelDelta = 0;
      if (e.deltaY > 0) {
        wheelDelta = -1; // 向下滚动
      } else if (e.deltaY < 0) {
        wheelDelta = 1;  // 向上滚动
      }
      
      if (wheelDelta !== 0) {
        console.log(`Mouse wheel: ${wheelDelta > 0 ? 'up' : 'down'}, delta: ${e.deltaY}`);
        sendMouseEvent(0, 0, 0, wheelDelta);
      }
    }

    // 快捷键处理
    function handleQuickKey() {
      const value = elements.quickKeys.value;
      if (!value || !isConnected) return;
      
      elements.quickKeys.value = '';
      
      const keyMappings = {
        'ctrl_alt_del': () => sendKeyCombo(['Control', 'Alt', 'Delete']),
        'alt_f4': () => sendKeyCombo(['Alt', 'F4']),
        'ctrl_c': () => sendKeyCombo(['Control', 'c']),
        'ctrl_v': () => sendKeyCombo(['Control', 'v']),
        'win_r': () => sendKeyCombo(['Meta', 'r'])
      };
      
      if (keyMappings[value]) {
        keyMappings[value]();
      }
    }

    async function sendKeyCombo(keys) {
      let modifiers = 0;
      let mainKey = 0;
      
      for (const key of keys) {
        if (MODIFIER_BITS[key]) {
          modifiers |= MODIFIER_BITS[key];
        } else {
          mainKey = KEY_CODES[key] || KEY_CODES[key.toLowerCase()] || 0;
        }
      }
      
      console.log(`Combo keys: ${keys.join('+')} -> KeyCode: 0x${mainKey.toString(16)}, Modifiers: 0x${modifiers.toString(16)}`);
      
      if (!serialPort) return;
      
      try {
        const writer = serialPort.writable.getWriter();
        
        // 按下
        await writer.write(createPacket(0x02, modifiers, 0, mainKey, 0, 0, 0, 0, 0));
        await new Promise(resolve => setTimeout(resolve, 10));
        
        // 释放
        await writer.write(createPacket(0x02, 0, 0, 0, 0, 0, 0, 0, 0));
        
        writer.releaseLock();
      } catch (error) {
        console.error('Send combo failed:', error);
      }
    }

    // 粘贴功能
    async function openPasteModal() {
      if (!isConnected) return;
      
      // 尝试从剪贴板读取文本
      try {
        if (navigator.clipboard && navigator.clipboard.readText) {
          const clipboardText = await navigator.clipboard.readText();
          if (clipboardText) {
            elements.pasteText.value = clipboardText;
          }
        }
      } catch (error) {
        console.log('Could not read clipboard:', error.message);
      }
      
      elements.pasteModal.classList.add('show');
      elements.pasteText.focus();
      elements.pasteText.select(); // 选中文本便于编辑
    }

    function closePasteModal() {
      elements.pasteModal.classList.remove('show');
      elements.pasteText.value = '';
    }

    async function sendPasteText() {
      const text = elements.pasteText.value;
      if (!text || !isConnected) return;
      
      closePasteModal();
      
      // 检查是否包含非ASCII字符
      const hasUnicode = [...text].some(char => char.charCodeAt(0) > 127);
      if (hasUnicode) {
        alert('检测到中文或特殊字符！\n\n由于这是串口模拟键盘，无法直接发送汉字。\n建议：\n1. 先在目标系统切换到中文输入法\n2. 然后手动输入中文\n3. 或者使用目标系统的粘贴功能\n\n现在将只发送ASCII字符部分。');
      }
      
      // 显示粘贴进度
      const originalStatus = elements.status.textContent;
      elements.status.textContent = `Pasting... (${text.length} chars)`;
      
      for (let i = 0; i < text.length; i++) {
        const char = text[i];
        
        // 更新进度
        if (i % 10 === 0) {
          elements.status.textContent = `Pasting... (${i}/${text.length})`;
        }
        
        // 只处理ASCII字符
        if (char.charCodeAt(0) <= 127) {
          const keyCode = KEY_CODES[char];
          if (!keyCode) {
            console.log('Unsupported ASCII char:', char);
            continue;
          }
          
          let modifiers = 0;
          // 检查是否需要Shift键
          if (SHIFT_CHARS.has(char)) {
            modifiers |= MODIFIER_BITS.Shift;
          }
          
          console.log(`Paste ASCII char: ${char}, KeyCode: 0x${keyCode.toString(16)}, Modifiers: 0x${modifiers.toString(16)}`);
          
          // 发送按下
          await sendKeyEvent(keyCode, modifiers, true);
          await new Promise(resolve => setTimeout(resolve, 30));
          
          // 发送释放 
          await sendKeyEvent(0, 0, false);
          await new Promise(resolve => setTimeout(resolve, 30));
        } else {
          // 跳过Unicode字符（汉字等）
          console.log(`Skipped Unicode char: ${char} (U+${char.charCodeAt(0).toString(16)})`);
        }
      }
      
      // 恢复状态显示
      elements.status.textContent = originalStatus;
      console.log('Paste completed');
    }

    // 鼠标锁定
    async function toggleMouseLock() {
      if (document.pointerLockElement) {
        document.exitPointerLock();
      } else {
        try {
          await elements.monitor.requestPointerLock();
        } catch (error) {
          console.error('Mouse lock failed:', error);
        }
      }
    }

    // 全屏
    function toggleFullscreen() {
      if (document.fullscreenElement) {
        document.exitFullscreen();
      } else {
        console.log('Requesting fullscreen...');
        elements.monitor.controls = false;
        elements.monitor.requestFullscreen().catch(e => {
          console.error('Fullscreen failed:', e);
        });
      }
    }

    // 分辨率显示模式切换
    function changeDisplayMode() {
      const mode = elements.resolutionSelect.value;
      
      // 清除所有模式类
      elements.monitor.classList.remove('original-size', 'fit-screen', 'stretch-fill');
      
      switch(mode) {
        case 'original':
          elements.monitor.classList.add('original-size');
          console.log('Display mode: Original Size');
          break;
        case 'fit':
          elements.monitor.classList.add('fit-screen');
          console.log('Display mode: Fit to Screen');
          break;
        case 'stretch':
          elements.monitor.classList.add('stretch-fill');
          console.log('Display mode: Stretch to Fill');
          break;
        default:
          // 默认模式：contain
          console.log('Display mode: Default (Contain)');
      }
      
      // 重置选择框
      elements.resolutionSelect.value = '';
    }

    // 帧率切换
    async function changeFrameRate() {
      const frameRate = parseInt(elements.framerateSelect.value);
      if (!frameRate || frameRate === currentFrameRate) {
        elements.framerateSelect.value = '';
        return;
      }
      
      currentFrameRate = frameRate;
      console.log('Frame rate changed to:', currentFrameRate, 'fps');
      
      // 如果正在捕获视频，重新启动以应用新帧率
      if (isCapturing && mediaStream) {
        const currentDeviceId = mediaStream.getVideoTracks()[0].getSettings().deviceId;
        
        // 停止当前流
        mediaStream.getTracks().forEach(track => track.stop());
        
        try {
          // 使用新帧率重新启动
          mediaStream = await navigator.mediaDevices.getUserMedia({
            video: {
              deviceId: { exact: currentDeviceId },
              frameRate: { ideal: currentFrameRate, min: Math.min(15, currentFrameRate) },
              width: { ideal: 1920, min: 1280 },
              height: { ideal: 1080, min: 720 }
            },
            audio: false
          });
          
          elements.monitor.srcObject = mediaStream;
          console.log('Video restarted with new frame rate:', currentFrameRate, 'fps');
          
        } catch (error) {
          console.error('Failed to change frame rate:', error);
          alert('帧率切换失败：' + error.message);
        }
      }
      
      // 重置选择框
      elements.framerateSelect.value = '';
    }

    // 鼠标灵敏度切换
    function changeMouseSensitivity() {
      const sensitivity = parseFloat(elements.sensitivitySelect.value);
      if (!sensitivity || sensitivity === mouseSensitivity) {
        elements.sensitivitySelect.value = '';
        return;
      }
      
      mouseSensitivity = sensitivity;
      console.log('Mouse sensitivity changed to:', mouseSensitivity + 'x');
      
      // 显示灵敏度变化提示
      const originalStatus = elements.status.textContent;
      elements.status.textContent = `Mouse: ${mouseSensitivity}x sensitivity`;
      setTimeout(() => {
        elements.status.textContent = originalStatus;
      }, 2000);
      
      // 重置选择框
      elements.sensitivitySelect.value = '';
    }

    // CapsLock同步功能
    async function syncCapsLock() {
      if (!isConnected) return;
      
      try {
        // 发送CapsLock按键来切换远程状态
        await sendKeyEvent(KEY_CODES.CapsLock, 0, true);
        await new Promise(resolve => setTimeout(resolve, 50));
        await sendKeyEvent(0, 0, false);
        
        console.log('CapsLock sync sent');
        alert('CapsLock状态已同步');
      } catch (error) {
        console.error('CapsLock sync failed:', error);
      }
    }

    // 测试Shift功能
    async function testShiftKey() {
      if (!isConnected) return;
      
      try {
        console.log('=== Testing Shift+A sequence (CORRECTED) ===');
        
        // 1. 清空状态
        await sendKeyEvent(0, 0, false);
        await new Promise(resolve => setTimeout(resolve, 50));
        
        // 2. 发送Shift+A组合键（只发送A键，但带Shift修饰符）
        // 注意：不要发送Shift键码，只使用修饰符！
        await sendKeyEvent(KEY_CODES.A, MODIFIER_BITS.Shift, true);
        await new Promise(resolve => setTimeout(resolve, 100));
        
        // 3. 释放A键
        await sendKeyEvent(0, 0, false);
        await new Promise(resolve => setTimeout(resolve, 50));
        
        console.log('=== Corrected test sequence completed ===');
        console.log('正确的方式：只发送目标键+修饰符，不发送修饰键本身');
        
        // 添加一个实际键盘事件测试
        console.log('=== Now please press Shift+B manually and watch the console ===');
        alert('修正后的测试序列已发送（应该输出大写A）。\n现在请手动按 Shift+B 组合键，对比两种方式的差异。');
      } catch (error) {
        console.error('Test failed:', error);
        alert('测试失败：' + error.message);
      }
    }
    
    // 测试完整的键盘序列
    function testKeyboardSequence() {
      if (!isConnected) {
        alert('请先连接设备');
        return;
      }
      
      console.log('=== Starting Keyboard Sequence Test ===');
      
      // 测试序列：Hello（大写H，小写ello）
      const sequence = [
        { key: KEY_CODES.H, modifier: MODIFIER_BITS.Shift, delay: 0 },    // H
        { key: KEY_CODES.E, modifier: 0, delay: 200 },                   // e
        { key: KEY_CODES.L, modifier: 0, delay: 200 },                   // l
        { key: KEY_CODES.L, modifier: 0, delay: 200 },                   // l
        { key: KEY_CODES.O, modifier: 0, delay: 200 },                   // o
        { key: KEY_CODES.Space, modifier: 0, delay: 200 },               // space
        { key: KEY_CODES.W, modifier: MODIFIER_BITS.Shift, delay: 200 }, // W
        { key: KEY_CODES.O, modifier: 0, delay: 200 },                   // o
        { key: KEY_CODES.R, modifier: 0, delay: 200 },                   // r
        { key: KEY_CODES.L, modifier: 0, delay: 200 },                   // l
        { key: KEY_CODES.D, modifier: 0, delay: 200 },                   // d
      ];
      
      let index = 0;
      function sendNext() {
        if (index >= sequence.length) {
          console.log('=== Keyboard Sequence Test Complete ===');
          return;
        }
        
        const item = sequence[index];
        console.log(`Sending key: 0x${item.key.toString(16)} with modifier: 0x${item.modifier.toString(16)}`);
        
        // 按下
        sendKeyEvent(item.key, item.modifier, true);
        
        setTimeout(() => {
          // 释放
          sendKeyEvent(item.key, item.modifier, false);
          
          index++;
          if (index < sequence.length) {
            setTimeout(sendNext, sequence[index].delay);
          } else {
            setTimeout(sendNext, 100);
          }
        }, 50);
      }
      
      setTimeout(sendNext, 500);
    }

    // 事件绑定
    elements.initBtn.addEventListener('click', initConnection);
    elements.captureBtn.addEventListener('click', startCapture);
    elements.deviceBtn.addEventListener('click', selectVideoDevice);
    elements.mouseBtn.addEventListener('click', toggleMouseLock);
    elements.fullscreenBtn.addEventListener('click', toggleFullscreen);
    elements.quickKeys.addEventListener('change', handleQuickKey);
    elements.pasteBtn.addEventListener('click', openPasteModal);
    elements.capsBtn.addEventListener('click', syncCapsLock);
    elements.resetBtn.addEventListener('click', clearAllKeyStates);
    elements.resolutionSelect.addEventListener('change', changeDisplayMode);
    elements.framerateSelect.addEventListener('change', changeFrameRate);
    elements.sensitivitySelect.addEventListener('change', changeMouseSensitivity);
    elements.testBtn.addEventListener('click', testShiftKey);
    elements.testSeqBtn.addEventListener('click', testKeyboardSequence);

    // 页面失去焦点时自动清理按键状态
    window.addEventListener('blur', () => {
      console.log('Window lost focus, clearing key states');
      clearAllKeyStates();
    });

    // 页面获得焦点时也清理一次（确保状态同步）
    window.addEventListener('focus', () => {
      console.log('Window gained focus, clearing key states');
      clearAllKeyStates();
    });

    // 监听Tab键切换（Alt+Tab等）可能导致的状态问题
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        console.log('Page hidden, clearing key states');
        clearAllKeyStates();
      }
    });

    // 键盘事件绑定到document而不是monitor，确保鼠标锁定时也能接收
    document.addEventListener('keydown', (e) => {
      // Ctrl+L 锁定/解锁鼠标
      if (e.ctrlKey && e.key === 'l') {
        e.preventDefault();
        toggleMouseLock();
        return;
      }
      
      // Ctrl+V 快捷粘贴（当不在monitor焦点时）
      if (e.ctrlKey && e.key === 'v' && document.activeElement !== elements.monitor && !document.pointerLockElement) {
        e.preventDefault();
        openPasteModal();
        return;
      }
      
      // ESC键退出全屏（如果没有被鼠标锁定占用）
      if (e.key === 'Escape' && document.fullscreenElement && !document.pointerLockElement) {
        e.preventDefault();
        toggleFullscreen();
        return;
      }
      
      // F11切换全屏
      if (e.key === 'F11') {
        e.preventDefault();
        toggleFullscreen();
        return;
      }
      
      // 如果monitor有焦点或者鼠标被锁定，处理键盘输入
      if (document.activeElement === elements.monitor || document.pointerLockElement) {
        handleKeyDown(e);
      }
    });

    document.addEventListener('keyup', (e) => {
      // 如果monitor有焦点或者鼠标被锁定，处理键盘输入
      if (document.activeElement === elements.monitor || document.pointerLockElement) {
        handleKeyUp(e);
      }
    });

    elements.monitor.addEventListener('mousemove', handleMouseMove);
    elements.monitor.addEventListener('mousedown', handleMouseDown);
    elements.monitor.addEventListener('mouseup', handleMouseUp);
    elements.monitor.addEventListener('mouseleave', handleMouseLeave);
    elements.monitor.addEventListener('contextmenu', handleContextMenu);
    elements.monitor.addEventListener('wheel', handleMouseWheel, { passive: false });

    // 添加鼠标锁定状态变化监听
    document.addEventListener('pointerlockchange', () => {
      const isLocked = document.pointerLockElement === elements.monitor;
      elements.mouseBtn.textContent = isLocked ? '🖱️ Unlock Mouse' : '🖱️ Lock Mouse';
      
      // 更新视觉状态
      if (isLocked) {
        elements.monitor.classList.add('mouse-locked');
        elements.monitor.focus();
        elements.inputStatus.classList.add('show');
      } else {
        elements.monitor.classList.remove('mouse-locked');
        elements.inputStatus.classList.remove('show');
        
        // 鼠标解锁时清理按钮状态
        if (currentMouseButtons !== 0) {
          currentMouseButtons = 0;
          if (isConnected && serialPort) {
            sendMouseEvent(0, 0, 0);
          }
          console.log('Mouse unlocked, clearing button states');
        }
      }
    });

    // 监听全屏状态变化
    document.addEventListener('fullscreenchange', () => {
      const isFullscreen = !!document.fullscreenElement;
      console.log('Fullscreen state changed:', isFullscreen);
      
      if (isFullscreen) {
        // 进入全屏时自动锁定鼠标
        setTimeout(() => {
          if (document.fullscreenElement && !document.pointerLockElement) {
            elements.monitor.requestPointerLock().catch(e => {
              console.error('Auto mouse lock failed:', e);
            });
          }
        }, 100); // 短暂延迟确保全屏完成
      }
    });

    // 监听monitor焦点变化
    elements.monitor.addEventListener('focus', () => {
      if (!document.pointerLockElement) {
        elements.inputStatus.classList.add('show');
      }
    });

    elements.monitor.addEventListener('blur', () => {
      if (!document.pointerLockElement) {
        elements.inputStatus.classList.remove('show');
      }
    });

    // 页面关闭时清理
    window.addEventListener('beforeunload', () => {
      if (serialPort) {
        serialPort.close().catch(() => {});
      }
      if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop());
      }
    });

    // 暴露给全局
    window.sendPasteText = sendPasteText;
    window.closePasteModal = closePasteModal;
    
    // 页面加载完成后的初始化
    window.addEventListener('load', () => {
      console.log('UsbKVM Pro loaded successfully');
      
      // 完全禁用视频播放器控件和交互
      elements.monitor.controls = false;
      elements.monitor.disablePictureInPicture = true;
      elements.monitor.setAttribute('controlsList', 'nodownload nofullscreen noremoteplayback');
      elements.monitor.removeAttribute('controls');
      
      // 强制禁用视频播放器的所有控制功能
      elements.monitor.setAttribute('tabindex', '-1');
      elements.monitor.style.pointerEvents = 'none';
      
      // 重新启用指针事件用于KVM控制
      setTimeout(() => {
        elements.monitor.style.pointerEvents = 'auto';
        elements.monitor.setAttribute('tabindex', '0');
      }, 100);
      
      console.log('Video controls completely disabled');
    });

    console.log('UsbKVM Pro - Professional WebUSB KVM Controller initialized');
  </script>
</body>
</html>
